#include <stdio.h>
#include <unistd.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
#include <fcntl.h>
#include <sys/socket.h>
#include <sys/types.h>
#include <arpa/inet.h>
#include <sys/epoll.h>
#include <netinet/tcp.h>
#include "InetAddress.h"
#include "Socket.h"
#include "Epoll.h"

void setnonblocking(int fd) {
    fcntl(fd, F_SETFL, fcntl(fd, F_GETFL) | O_NONBLOCK);
}

void str_toupper(char *buf, int len) {
    for (int i = 0; i < len; ++i)
        if (buf[i] >= 'a' && buf[i] <= 'z')
            buf[i] -= 32;
}

int main(int argc, char* argv[]) {
    // if (argc != 3) {
    //     printf("usage: ./tcpepoll ip port\n");
    //     return -1;
    // }

    Socket servsock(createnonblocking());
    servsock.setkeepalive(true);
    servsock.setreuseaddr(true);
    servsock.setreuseport(true);
    servsock.settcpnodelay(true);

    InetAddress servaddr("127.0.0.1",atoi("5085"));
    servsock.bind(servaddr);
    servsock.listen();

    
    Epoll epoll;
    epoll.addfd(servsock.fd(),EPOLLIN);
    std::vector<epoll_event> events;


    while (1) {

        // int infds = epoll_wait(epollfd, evs, 1024, -1);
        events = epoll.loop();


        for (auto &ev : events) {
            int curfd = ev.data.fd;

            if (curfd == servsock.fd()) {
     
                InetAddress clientaddr;
                /*
                注意：只能new 否则析构函数会关闭fd
                还有，这里new出来的对象没有释放，这个问题以后再解决
                */
                Socket* clientsock = new Socket(servsock.accept(clientaddr));

                if (clientsock->fd() < 0) {
                    if (errno == EAGAIN || errno == EWOULDBLOCK)
                        break;  // 没有更多连接
                    perror("accept() failed");
                    break;
                    
                }

                printf("New client connected: %s:%d\n", clientaddr.ip().c_str(), clientaddr.port());

                epoll.addfd(clientsock->fd(),EPOLLIN | EPOLLET);

                
            } else {
                // 处理客户端数据（边缘触发必须读到EAGAIN）
                char buf[1024];
                while (1) {
                    ssize_t n = read(curfd, buf, sizeof(buf));
                    if (n < 0) {
                        if (errno == EAGAIN || errno == EWOULDBLOCK)
                            break;  // 所有数据读完
                        perror("read() error");
                        // 先下树，再关闭
                        epoll.delfd(curfd);
                        close(curfd);
                        break;
                    } else if (n == 0) {
                        printf("Client disconnected, fd=%d\n", curfd);
                        
                        epoll.delfd(curfd);
                        close(curfd);
                        break;
                    } else {
                        str_toupper(buf, n);  // 转大写
                        write(curfd, buf, n); // 写回
                    }


                }
            }
        }
    }

    //close(listenfd);
    return 0;
}
